import os
import uuid
import hashlib
import time
import dbm.dumb
import json
from typing import Optional


from fastapi import UploadFile, Request, Form, Query, APIRouter, Depends, Security
from fastapi.responses import FileResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel

from check_user import router as userRouter
from check_user import check_user

from account.user_management import create_user_token
from auth import get_user_token


TEST_PATH = "./test_files"

router = APIRouter()
template = Jinja2Templates(directory="./")


@router.get("/", name="allfiles", dependencies=[Security(check_user, scopes=["visit"])])
def allfiles(request: Request):
    files = []
    try:
        db = dbm.dumb.open(f'{TEST_PATH}/test_dbm', 'c')
        if db:
            for k in db.keys():
                file = json.loads(db[k])
                files.append(file)
    except:
        pass
    return template.TemplateResponse("test_dropbox.html", {"request": request, "files": files})


@router.post("/upload_file", name="upload_file", dependencies=[Security(check_user, scopes=["upload"])])
async def upload_file(*, file: UploadFile,
                      code: Optional[str] = Form(max_length=8),
                      request: Request):
    info = {
        'file_name': file.filename,
        'file_size': file.size,
        'content_type': file.content_type,
        'upload_time': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
        'unique_name': get_unique_name(file),
        'share_code': code or hashlib.md5(uuid.uuid4().bytes).hexdigest()[:6],
    }
    await store_indbm(info)
    await save_files(file)
    template.TemplateResponse(
        "test_dropbox.html", {"request": request})
    return RedirectResponse(request.url_for("allfiles"), status_code=303)


@router.post("/download", name="download_file", dependencies=[Security(check_user, scopes=["download"])])
async def download_file(unique_name: Optional[str] = Query(), share_code: str = Form(...)):
    db = dbm.dumb.open(f'{TEST_PATH}/test_dbm', 'c')
    info = json.loads(db[unique_name])
    if share_code != info['share_code']:
        db.close()
        return {"error": "wrong share code"}
    db.close()
    full_name = os.path.join(TEST_PATH, info['file_name'])
    return FileResponse(full_name, filename=info['file_name'])


# @router.get("/sendtoken")
# def send_token(request: Request):
#     data = {
#         "username": "jack",
#     }
#     token = create_user_token(data)
#     return {"token": token}


# @router.get("/gettoken")
# def get_token(token: str = Depends(get_user_token)):
#     return {"token": token}


def get_unique_name(file: UploadFile):
    file.unique_name = hashlib.md5(uuid.uuid4().bytes).hexdigest()[:8]
    return file.unique_name


async def store_indbm(info) -> None:
    if not os.path.exists(TEST_PATH):
        os.makedirs(TEST_PATH)
    unique_name = info['unique_name']
    json_info = json.dumps(info).encode('utf-8')
    db = dbm.dumb.open(f'{TEST_PATH}/test_dbm', 'c')
    db[unique_name] = json_info
    db.close()


async def save_files(file) -> str:
    if not os.path.exists(TEST_PATH):
        os.makedirs(TEST_PATH)
    res = await file.read()
    full_name = os.path.join(TEST_PATH, file.filename)
    with open(full_name, 'wb') as f:
        f.write(res)
    return full_name
